package application.mvc.biz.cabinet;

import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import com.jfinal.ext.kit.DateKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import application.common.constant.MessageType;
import application.common.constant.SceneType;
import application.common.model.Board;
import application.common.model.Cabinet;
import application.common.model.FaultBox;
import application.common.model.Store;
import application.common.model.StoreBox;
import application.common.model.StoreBoxLog;
import application.common.model.StoreLog;
import application.common.model.StoreUser;
import application.common.plugins.serialPort.SerialCommunication;
import application.common.render.Cmd;
import application.common.ui.ProgressStage;
import application.common.util.CmdUtil;
import application.common.util.Convert;
import application.common.util.ExtDbUtil;
import application.common.util.LayerUtil;
import application.common.util.RouteUtil;
import application.common.util.ShiroUtil;
import application.common.util.StoreUtil;
import application.common.util.UuidUtil;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.RotateTransition;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.util.Duration;

public class CabinetController implements Initializable {

	private final Log log = Log.getLog(getClass());

	private StringProperty storeId = new SimpleStringProperty();

	private ObjectProperty<Cabinet> cabinet = new SimpleObjectProperty<Cabinet>();

	@FXML
	private Label headerLabel;

	@FXML
	private Label copyrightLabel;

	@FXML
	private Label messageLabel;

	@FXML
	private Button openBoxBtn;

	@FXML
	private ImageView portraitImageView;

	@FXML
	private Label usernameLabel;

	@FXML
	private Label roleNameLabel;

	@FXML
	private Label cabinetHeaderLabel;
	
	@FXML
	private FlowPane buttonsFlowPane;

	@FXML
	private Pane timerOutLinePane;

	@FXML
	private Pane timerInLinePane;

	@FXML
	private Label timerLabel;
	private Timeline animation;
	private RotateTransition rotateTransitionOut;
	private RotateTransition rotateTransitionIn;

	private SerialCommunication serialCommunication;

	private Map<String, Button> boxMap = new HashMap<String, Button>();

	// 存储
	private Store store;
	
	private boolean isDestroy;

	private ObservableList<Button> dataList = FXCollections.observableArrayList();

	public CabinetController(String archiveNo, Cabinet cabinet) {
		this.storeId.set(archiveNo);
		this.cabinet.set(cabinet);
	}

	public void initialize(URL arg0, ResourceBundle arg1) {
		headerLabel.setText(ShiroUtil.getSoftName());
		copyrightLabel.setText(ShiroUtil.getCopyright());
		portraitImageView.setImage(ShiroUtil.getUser().getPortrait());
		usernameLabel.setText(ShiroUtil.getUser().getName());
		roleNameLabel.setText(ShiroUtil.getUser().getRoleName());
		cabinetHeaderLabel.setText(cabinet.get().getName());
		ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
			@Override
			protected Void call() throws Exception {
				
				store = Store.dao.findById(storeId.get());
				if (store == null) {
					store = new Store();
				}
				pareFaultBox();
				pareUsedBox();
				pareSameBox();
				log.info(String.format("存储卷宗【%s】|存储柜子【%s】", storeId.get(), cabinet.get().getName()));
				if (cabinet.get().getBoards() != null && cabinet.get().getBoards().size() > 0) {
					int boxNo=0;
					Button button = null;
					for(int r=1;r<=5;r++) {
						for(Board board : cabinet.get().getBoards()) {
							for(int i=0;i<board.getBoxTotal();i++) {
								boxNo++;
								if (StrKit.equals("1", cabinet.get().getType())) {
									button = new Button();
									button.setPrefSize(70, 180);
									
									button.setAccessibleText((r+i*5)+"");
									button.setAccessibleHelp(board.getId());
									button.setAccessibleRoleDescription(UuidUtil.getUUID());
									button.setText(cabinet.get().getCode() + boxNo);
									
									boxMap.put(button.getAccessibleRoleDescription(), button);
								} else if (StrKit.equals("2", cabinet.get().getType())) {
									button = new Button();
									button.setPrefSize(107.0, 180);
									
									button.setAccessibleText((r+i*5)+"");
									button.setAccessibleHelp(board.getId());
									button.setAccessibleRoleDescription(UuidUtil.getUUID());
									button.setText(cabinet.get().getCode() + boxNo);
									
									boxMap.put(button.getAccessibleRoleDescription(), button);
								} else if (StrKit.equals("3", cabinet.get().getType())) {
									button = new Button();
									button.setPrefSize(220.0, 180);
									
									button.setAccessibleText((r+i*5)+"");
									button.setAccessibleHelp(board.getId());
									button.setAccessibleRoleDescription(UuidUtil.getUUID());
									button.setText(cabinet.get().getCode() + boxNo);
									
									boxMap.put(button.getAccessibleRoleDescription(), button);
									
								}
								if (button != null) {
									if(sameBoxMap.containsKey(board.getId()) && sameBoxMap.get(board.getId()).contains((r+i*5))) {
										button.setId("cabinet-btn-same");
									}
									else if(usedBoxMap.containsKey(board.getId()) && usedBoxMap.get(board.getId()).contains((r+i*5)))  {
										button.setId("cabinet-btn-used");
									} 
									else if(faultBoxMap.containsKey(board.getId()) && faultBoxMap.get(board.getId()).contains((r+i*5))) {
										button.setId("cabinet-btn-fault");
									} else {
										button.setId("cabinet-btn");
										button.setOnAction(new EventHandler<ActionEvent>() {
											public void handle(ActionEvent event) {
												Button btn = (Button) event.getSource();
												selected(btn,btn.getAccessibleRoleDescription());
											}
										});
									}
									dataList.add(button);
								}
								if((i+1)*5>=board.getBoxTotal()) {
									break;
								}
							}
						}
					}
					
					Platform.runLater(new Runnable() {
					    public void run() {
					    	buttonsFlowPane.getChildren().addAll(dataList);
					    }
					});
					
					try {
						initializeSerialPort();
						boolean isOK = serialCommunication.startComPort();
						if (!isOK) {
							goMessage(String.format("【%s】初始化异常！", cabinet.get().getName()));
							return null;
						}
						log.info( String.format("【%s】初始化成功！", cabinet.get().getName()));
						start();
					}catch (Exception e) {
						log.error( String.format("【%s】初始化异常", cabinet.get().getName()),e);
						goMessage(String.format("【%s】初始化异常", cabinet.get().getName()));
						return null;
					}
				} else {
					goMessage(String.format("【%s】未配置板卡！", cabinet.get().getName()));
				}
				return null;
			}
		}, "初始化【"+cabinet.get().getName()+"】中...").show();

	}
	
	public void start() {
		if(!isDestroy) {
			rotateTransitionOut = new RotateTransition(Duration.seconds(10), timerOutLinePane);
			rotateTransitionOut.setFromAngle(0);
			rotateTransitionOut.setToAngle(360);
			rotateTransitionOut.setByAngle(360); // 设置旋转的角度
			rotateTransitionOut.setCycleCount(Animation.INDEFINITE); // 设置旋转次数，我们需要旋转无数次
			rotateTransitionOut.setInterpolator(Interpolator.LINEAR);
			rotateTransitionOut.play();

			rotateTransitionIn = new RotateTransition(Duration.seconds(10), timerInLinePane);
			rotateTransitionIn.setFromAngle(360);
			rotateTransitionIn.setToAngle(0);
			rotateTransitionIn.setByAngle(360); // 设置旋转的角度
			rotateTransitionIn.setCycleCount(Animation.INDEFINITE); // 设置旋转次数，我们需要旋转无数次
			rotateTransitionIn.setInterpolator(Interpolator.LINEAR);
			rotateTransitionIn.play();
			startCountDown();
		}
	}
	
	/**
	 * 消息页面
	 * @param message
	 */
	public void goMessage(String message) {
		log.info(message);
		Platform.runLater(new Runnable() {
		    public void run() {
				ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
					@Override
					protected Void call() throws Exception {
						destroy();
						RouteUtil.goMessage(MessageType.ERROR, message, SceneType.CABINET);
						return null;
					}
				},"跳转消息页面中...").show();
		    }
		});
	}

	public void exit(ActionEvent event) {
		if(!isDestroy) {
			isDestroy=true;
			if (openBoxMap.size() == 0) {
				log.info(String.format("存储卷宗【%s】|存储柜子【%s】,未操作！", storeId.get(), cabinet.get().getName()));
				ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
					@Override
					protected Void call() throws Exception {
						destroy();
						RouteUtil.goCabGroup(storeId.get(), false);
						return null;
					}
				},"前往柜子组中...").show();
			} else {
				this.doSave();
			}
		}
	}

	public void next(ActionEvent event) {
		if (selectedBoxMap.size() > 0) {
			this.doOpen();
		} else {
			message("请选择存储位置！", false);
		}
	}

	public void startCountDown() {
		animation = new Timeline(new KeyFrame(Duration.millis(1000), new EventHandler<ActionEvent>() {
			public void handle(ActionEvent event) {
				if(RouteUtil.getTime()>0) {
					RouteUtil.setTime(RouteUtil.getTime() - 1);
					if (RouteUtil.getTime() == 0) {
						timerLabel.setText("0");
						LayerUtil.open("操作超时！", 999);
					} else if (RouteUtil.getTime() > 0) {
						timerLabel.setText(RouteUtil.getTime() + "");
					}
				}
				
			}
		}));
		animation.setCycleCount(Timeline.INDEFINITE);
		animation.play();
	}

	public void destroy() {
		if (animation != null) {
			animation.stop();
		}
		if (rotateTransitionOut != null) {
			rotateTransitionOut.stop();
		}
		if (rotateTransitionIn != null) {
			rotateTransitionIn.stop();
		}
		if (serialCommunication != null) {
			serialCommunication.release();
		}
	}

	public void message(final String message, final boolean isOK) {
		Platform.runLater(new Runnable() {
			public void run() {
				messageLabel.setText(message);
				if (isOK) {
					messageLabel.setId("message-label");
				} else {
					messageLabel.setId("message-label-error");
				}
			}
		});

	}

	public void visibleOpenBoxBtn(final boolean isOK) {
		Platform.runLater(new Runnable() {
			public void run() {
				if (isOK) {
					if (!openBoxBtn.isVisible())
						openBoxBtn.setVisible(true);
				} else {
					if (openBoxBtn.isVisible())
						openBoxBtn.setVisible(false);
				}
			}
		});

	}

	private Map<String,List<Integer>> faultBoxMap =  new HashMap<String,List<Integer>>();

	/**
	 * 故障
	 */
	public void pareFaultBox() {
		List<FaultBox> faultBoxs = FaultBox.dao.find("select * from " + FaultBox.TABLE_NAME + " where cabinetId=? ", cabinet.get().getId());
		if (faultBoxs != null && faultBoxs.size()>0) {
			List<Integer> errors;
			for(FaultBox faultBox:faultBoxs) {
				if(faultBoxMap.containsKey(faultBox.getBoardId())) {
					errors=faultBoxMap.get(faultBox.getBoardId());
					if(!errors.contains(faultBox.getBoxNo())) {
						errors.add(faultBox.getBoxNo());
						faultBoxMap.put(faultBox.getBoardId(), errors);
					}
				}else {
					errors = new LinkedList<Integer>();
					errors.add(faultBox.getBoxNo());
					faultBoxMap.put(faultBox.getBoardId(), errors);
				}
			}
		}
	}
	
	private Map<String,List<Integer>> usedBoxMap =  new HashMap<String,List<Integer>>();

	/**
	 * 占用
	 */
	public void pareUsedBox() {
		List<StoreBox> storeBoxs = StoreBox.dao.find("select * from " + StoreBox.TABLE_NAME + " where cabinetId=? ", cabinet.get().getId());
		if (storeBoxs != null && storeBoxs.size()>0) {
			List<Integer> usedBoxs;
			for(StoreBox storeBox:storeBoxs) {
				if(usedBoxMap.containsKey(storeBox.getBoardId())) {
					usedBoxs=usedBoxMap.get(storeBox.getBoardId());
					if(!usedBoxs.contains(storeBox.getBoxNo())) {
						usedBoxs.add(storeBox.getBoxNo());
						usedBoxMap.put(storeBox.getBoardId(), usedBoxs);
					}
				}else {
					usedBoxs = new LinkedList<Integer>();
					usedBoxs.add(storeBox.getBoxNo());
					usedBoxMap.put(storeBox.getBoardId(), usedBoxs);
				}
			}
		}
	}

	private Map<String,List<Integer>> sameBoxMap = new HashMap<String,List<Integer>>();

	/**
	 * 相同
	 */
	public void pareSameBox() {
		List<StoreBox> storeBoxs = StoreBox.dao.find("select * from " + StoreBox.TABLE_NAME + " where cabinetId=? and storeId=? ", cabinet.get().getId(),storeId.get());
		if (storeBoxs != null && storeBoxs.size()>0) {
			List<Integer> sameBoxs;
			for(StoreBox storeBox:storeBoxs) {
				if(sameBoxMap.containsKey(storeBox.getBoardId())) {
					sameBoxs=sameBoxMap.get(storeBox.getBoardId());
					if(!sameBoxs.contains(storeBox.getBoxNo())) {
						sameBoxs.add(storeBox.getBoxNo());
						sameBoxMap.put(storeBox.getBoardId(), sameBoxs);
					}
				}else {
					sameBoxs = new LinkedList<Integer>();
					sameBoxs.add(storeBox.getBoxNo());
					sameBoxMap.put(storeBox.getBoardId(), sameBoxs);
				}
			}
		}
	}

	/**
	 * 勾选存放柜子
	 */
	private Map<String, Button> selectedBoxMap = new HashMap<String, Button>();

	public void selected(Button button, String key) {
		if (selectedBoxMap.containsKey(key)) {
			selectedBoxMap.remove(key);
			changeBtn(button,"cabinet-btn");
		} else {
			changeBtn(button,"cabinet-btn-selected");
			selectedBoxMap.put(key, button);
		}
		if (selectedBoxMap.size() == 0) {
			message("请选择存储位置！", true);
			visibleOpenBoxBtn(false);
		} else {
			message("已选择【" + selectedBoxMap.size() + "】存储位置！", true);
			visibleOpenBoxBtn(true);
		}
	}
	
	private void changeBtn(Button button,String styleId) {
		Platform.runLater(new Runnable() {
			public void run() {
				if(!StrKit.isBlank(styleId)) {
					button.setId(styleId);
				}
			}
		});
	}
	
	private void changeBtn(Button button,String styleId,EventHandler<ActionEvent> onAction) {
		Platform.runLater(new Runnable() {
			public void run() {
				if(!StrKit.isBlank(styleId)) {
					button.setId(styleId);
				}
				button.setOnAction(onAction);
			}
		});
	}
	
	private void changeBtn(Button button,String styleId,EventHandler<ActionEvent> onAction,boolean isDisable) {
		Platform.runLater(new Runnable() {
			public void run() {
				if(!StrKit.isBlank(styleId)) {
					button.setId(styleId);
				}
				button.setOnAction(onAction);
				button.setDisable(isDisable);
			}
		});
	}
	
	/**
	 * 开启的柜子
	 */
	private Map<String, Cmd> openBoxMap = new HashMap<String, Cmd>();
	public void doOpen() {
		ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
			@Override
			protected Void call() throws Exception {
				java.util.Iterator<String> it = selectedBoxMap.keySet().iterator();
				while (it.hasNext()) {
					String key = it.next();
					Button button = selectedBoxMap.get(key);
					Board board = Board.dao.findById(button.getAccessibleHelp());
					if (board != null) {
						currCmd=new Cmd(board.getCabinetId(),board.getId(),board.getBoardNo(),button.getText(),key,Integer.parseInt(button.getAccessibleText()),0);
						if (!sendOpenCMD()) {
							changeBtn(button,"cabinet-btn-fault",null,true);
						}else {
							if(currCmd.getStatus()==1) {
								if(!openBoxMap.containsKey(currCmd.getBoxNo())) {
									openBoxMap.put(key, currCmd);
								}
								changeBtn(button,"cabinet-btn-open",null);
							}else {
								changeBtn(button,"cabinet-btn-fault",null,true);
							}
						}
					} else {
						log.info(String.format("存储柜子【%s】，柜子编号【%s】，未找到板卡信息", cabinet.get().getName(), key));
						changeBtn(button,"cabinet-btn-fault",null,true);
					}
				}
				selectedBoxMap.clear();
				visibleOpenBoxBtn(false);
				message(String.format("总共开启【%s】，目前关闭【%s】，暂未关闭【%s】，存储【%s】,未用【%s】！！", openBoxMap.size(),closeBoxMap.size(),openBoxMap.size()-closeBoxMap.size(),
						existBoxMap.size(), openBoxMap.size()-existBoxMap.size()), true);
				return null;
			}
		}, "正在开箱，请稍后...").show();
	}

	/**
	 * 存储
	 */
	public void doSave() {
		ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
			@Override
			protected Void call() throws Exception {
				
				try {
					ExtDbUtil.beginTran();
					existBoxMap.clear();
					closeBoxMap.clear();
					
					StoreBox storeBox;
					List<StoreBox> storeBoxs=new LinkedList<StoreBox>();
					StoreBoxLog storeBoxLog;
					List<StoreBoxLog> storeBoxLogs=new LinkedList<StoreBoxLog>();
					
					java.util.Iterator<String> it = openBoxMap.keySet().iterator();
					while (it.hasNext()) {
						String key = it.next();
						currCmd = openBoxMap.get(key);
						log.info("---------------------检测存储和闭合【开始】--------------------------");
						sendCloseCMD();
						log.info("---------------------检测存储和闭合【完成】--------------------------");
						storeBoxLog=new StoreBoxLog();
						storeBoxLog.setId(UuidUtil.getUUID());
						storeBoxLog.setCabinetId(cabinet.get().getId());
						storeBoxLog.setBoardId(openBoxMap.get(key).getBoardId());
						storeBoxLog.setBoxNo(openBoxMap.get(key).getRealNo());
						storeBoxLog.setStoreId(storeId.get());
						storeBoxLog.setStatus("0");
						storeBoxLog.setCreateTime(DateKit.toStr(new Date(System.currentTimeMillis()), "yyyy-MM-dd hh:mm:ss"));
						storeBoxLogs.add(storeBoxLog);
						
					}
					
					String msg=String.format("总共开启【%s】，目前关闭【%s】，暂未关闭【%s】，存储【%s】,未用【%s】！！", openBoxMap.size(),closeBoxMap.size(),openBoxMap.size()-closeBoxMap.size(),
							existBoxMap.size(), openBoxMap.size()-existBoxMap.size());
					if(closeBoxMap.size()!=openBoxMap.size()) {
						throw new Exception(msg);
					}
					
					if(existBoxMap.size()<=0) {
						isDestroy=false;
						destroy();
						RouteUtil.goCabGroup(storeId.get(), false);
						log.info(String.format("存储卷宗【%s】|存储柜子【%s】,未操作！", storeId.get(), cabinet.get().getName()));
						return null;
					}
					
					Cmd exisCmd ;
					java.util.Iterator<String>  exisIt = existBoxMap.keySet().iterator();
					List<Integer> sameBoxs;
					while (exisIt.hasNext()) {
						String key = exisIt.next();
						exisCmd = existBoxMap.get(key);
						if(sameBoxMap.containsKey(exisCmd.getBoardId())) {
							sameBoxs=sameBoxMap.get(exisCmd.getBoardId());
							if(!sameBoxs.contains(exisCmd.getRealNo())) {
								
								storeBox=new StoreBox();
								storeBox.setId(UuidUtil.getUUID());
								storeBox.setCabinetId(cabinet.get().getId());
								storeBox.setBoardId(exisCmd.getBoardId());
								storeBox.setBoxNo(exisCmd.getRealNo());
								storeBox.setStoreId(storeId.get());
								storeBoxs.add(storeBox);
								
								storeBoxLog=new StoreBoxLog();
								storeBoxLog.setId(UuidUtil.getUUID());
								storeBoxLog.setCabinetId(cabinet.get().getId());
								storeBoxLog.setBoardId(exisCmd.getBoardId());
								storeBoxLog.setBoxNo(exisCmd.getRealNo());
								storeBoxLog.setStoreId(storeId.get());
								storeBoxLog.setStatus("1");
								storeBoxLog.setCreateTime(DateKit.toStr(new Date(System.currentTimeMillis()), "yyyy-MM-dd hh:mm:ss"));
								storeBoxLogs.add(storeBoxLog);
							}
						}else {
							storeBox=new StoreBox();
							storeBox.setId(UuidUtil.getUUID());
							storeBox.setCabinetId(cabinet.get().getId());
							storeBox.setBoardId(exisCmd.getBoardId());
							storeBox.setBoxNo(exisCmd.getRealNo());
							storeBox.setStoreId(storeId.get());
							storeBoxs.add(storeBox);
							
							storeBoxLog=new StoreBoxLog();
							storeBoxLog.setId(UuidUtil.getUUID());
							storeBoxLog.setCabinetId(cabinet.get().getId());
							storeBoxLog.setBoardId(exisCmd.getBoardId());
							storeBoxLog.setBoxNo(exisCmd.getRealNo());
							storeBoxLog.setStoreId(storeId.get());
							storeBoxLog.setStatus("1");
							storeBoxLog.setCreateTime(DateKit.toStr(new Date(System.currentTimeMillis()), "yyyy-MM-dd hh:mm:ss"));
							storeBoxLogs.add(storeBoxLog);
						}

					}
					log.info(String.format("保存卷宗存储信息，卷宗号【%s】.",storeId.get()));
					String operationType;
					Store store = Store.dao.findById(storeId.get());
					if (store == null) {
						store = new Store();
						store.setId(storeId.get());
						if(!store.save()) {
							throw new Exception(String.format("保存卷宗存储信息异常，卷宗号【%s】.",storeId.get()));
						}
						operationType="0";
					}else {
						operationType="1";
					}
					
					log.info(String.format("保存卷宗存储明细，卷宗号【%s】.",storeId.get()));
					
					for(StoreBox item:storeBoxs) {
						if(!item.save()) {
							throw new Exception(String.format("保存卷宗存储明细异常，卷宗号【%s】.",storeId.get()));
						}
					}
					log.info(String.format("保存卷宗存储明细成功，卷宗号【%s】.",storeId.get()));
					
					log.info(String.format("记录操作人信息，卷宗号【%s】.",storeId.get()));
					StoreUser storeUser = StoreUser.dao.findFirst("select * from " + StoreUser.TABLE_NAME + " where userId=? and storeId=? ",ShiroUtil.getUser().getId(), storeId.get());
					if (storeUser == null) {
						storeUser = new StoreUser();
						storeUser.setId(UuidUtil.getUUID());
						storeUser.setStoreId(storeId.get());
						storeUser.setUserId(ShiroUtil.getUser().getId());
						storeUser.setSrc("1");
						if (!storeUser.save()) {
							throw new Exception(String.format("保存卷宗操作人异常，卷宗号【%s】.",storeId.get()));
						}
					}
					log.info(String.format("保存卷宗操作人成功，卷宗号【%s】.",storeId.get()));
					
					log.info(String.format("记录存储日志，卷宗号【%s】.",storeId.get()));
					StoreLog storeLog = new StoreLog();
					storeLog.setId(UuidUtil.getUUID());
					storeLog.setCabinetId(cabinet.get().getId());
					storeLog.setStoreId(storeId.get());
					storeLog.setUserId(ShiroUtil.getUser().getId());
					storeLog.setStatus(operationType);
					if (!storeLog.save()) {
						throw new Exception(String.format("记录存储日志异常，卷宗号【%s】.",storeId.get()));
					}
					log.info(String.format("记录存储日志成功，卷宗号【%s】.",storeId.get()));
					log.info(String.format("记录存储明细日志，卷宗号【%s】.",storeId.get()));
					for(StoreBoxLog item:storeBoxLogs) {
						item.setLogId(storeLog.getId());
						if(!item.save()) {
							throw new Exception(String.format("记录存储明细日志异常，卷宗号【%s】.",storeId.get()));
						}
					}
					
					try {
						StoreUtil.pull(storeId.get());
					}catch (Exception e) {
					}
					
					log.info(String.format("记录存储明细日志成功，卷宗号【%s】.",storeId.get())); 
					destroy();
					RouteUtil.goArchives();
					ExtDbUtil.commit();
				}catch (Exception e) {
					try {
						ExtDbUtil.rollback();
					} catch (SQLException e1) {
						log.error("事务回滚异常",e1);
					}
					message(e.getMessage(), false);
					isDestroy=false;
					log.info(e.getMessage());
				}
				return null;
			}
		}, "正在存储，请稍后...").show();
	}
	
	/**********************************************************************************/
	protected void initializeSerialPort() {
		serialCommunication = new SerialCommunication(cabinet.get(), new SerialPortEventListener() {
			public void serialEvent(SerialPortEvent event) {
				switch (event.getEventType()) {
				case SerialPortEvent.BI:// 通讯中断
				case SerialPortEvent.OE:// 7 溢位（溢出）错误
				case SerialPortEvent.FE:// 9 帧错误
				case SerialPortEvent.PE:// 8 奇偶校验错误
				case SerialPortEvent.CD:// 6 载波检测
				case SerialPortEvent.CTS:// 3 清除待发送数据
				case SerialPortEvent.DSR:// 4 待发送数据准备好了
				case SerialPortEvent.RI: // 5 振铃指示
				case SerialPortEvent.OUTPUT_BUFFER_EMPTY:// 2 输出缓冲区已清空
					break;
				case SerialPortEvent.DATA_AVAILABLE:// 1 串口存在可用数据
					try {
						   int bufflenth = serialCommunication.getInputStream().available();//获得数据长度
						   byte[] bget;
						   while (bufflenth > 0) {
							 bget = new byte[bufflenth];
							 serialCommunication.getInputStream().read(bget);
			                 bufflenth = serialCommunication.getInputStream().available();
			                 onReceive(bget);
				           }
					} catch (IOException e) {
					}
					break;
				}
			}
		});
	}

	private Cmd currCmd;
	private boolean cmdOK;
	private boolean sendOpenCMD() {
		if (serialCommunication != null) {
			cmdOK = false;
			log.info(String.format("开柜：端口【%s】- 板卡【%s】- 柜号【%s】", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
			boolean isSucc = serialCommunication.sendCMD(CmdUtil.getOpen(currCmd.getRealNo(), currCmd.getBoardNo()));
			log.info(String.format("开柜：端口【%s】- 板卡【%s】- 柜号【%s】- 命令【%s】", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo(),isSucc+""));
			if (isSucc) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
				}
				if(!isTimeout()) {
					log.info(String.format("状态：端口【%s】- 板卡【%s】- 柜号【%s】", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
					cmdOK = false;
					currCmd.setModel(0);
					isSucc = serialCommunication.sendCMD(CmdUtil.getOpenStatus(currCmd.getRealNo(), currCmd.getBoardNo()));
					if (isSucc) {
						log.info("发送开启状态检测命令成功！");
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
						}
						if(!isTimeout()) {
							log.info("发送开启状态检测命令成功,cmdOK="+cmdOK);
							return 1==currCmd.getStatus();
						}else {
							log.info("发送开柜指令无响应！");
							return false;
						}
					} else {
						log.info("发送开启状态检测命令失败！");
						return false;
					}
				}else {
					log.info("发送开柜指令无响应！");
					return false;
				}
			} else {
				return isSucc;
			}
		}
		return false;
	}
	
	private Map<String, Cmd> existBoxMap = new HashMap<String, Cmd>();
	private Map<String, Cmd> closeBoxMap = new HashMap<String, Cmd>();
	
	private boolean sendCloseCMD() {
		if (serialCommunication != null) {
			cmdOK = false;
			currCmd.setModel(2);
			currCmd.setStatus(0);
			log.info(String.format("存储：端口【%s】- 板卡【%s】- 柜号【%s】", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
			boolean isSucc = serialCommunication.sendCMD(CmdUtil.getSaveStatus(currCmd.getRealNo(), currCmd.getBoardNo()));
			if (isSucc) {
				log.info(String.format("存储：端口【%s】- 板卡【%s】- 柜号【%s】-发送成功", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
				}
				if(!isTimeout()) {
					if(1==currCmd.getStatus()) {
						if(!existBoxMap.containsKey(currCmd.getBoxNo())) {
							existBoxMap.put(currCmd.getBoxNo(),currCmd);
						}
					}
					log.info(String.format("存储：端口【%s】- 板卡【%s】- 柜号【%s】-发送成功-返回【%s】.", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo(),(1==currCmd.getStatus()?"有物品":"无物品")));
					cmdOK = false;
					currCmd.setModel(1);
					currCmd.setStatus(0);
					log.info(String.format("状态（send）：端口【%s】- 板卡【%s】- 柜号【%s】-发送成功", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
					isSucc = serialCommunication.sendCMD(CmdUtil.getOpenStatus(currCmd.getRealNo(), currCmd.getBoardNo()));
					if (isSucc) {
						log.info(String.format("状态（send）：端口【%s】- 板卡【%s】- 柜号【%s】", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
						}
						if (!isTimeout()) {
							if(1==currCmd.getStatus()) {
								log.info(String.format("状态(response)：端口【%s】- 板卡【%s】- 柜号【%s】- 结果【%s】", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo(),currCmd.getStatus()));
								if(!closeBoxMap.containsKey(currCmd.getBoxNo())) {
									closeBoxMap.put(currCmd.getBoxNo(),currCmd);
									if(existBoxMap.containsKey(currCmd.getBoxNo())) {
										changeBtn(boxMap.get(currCmd.getBoxNo()),"cabinet-btn-same",null);
									}else {
										changeBtn(boxMap.get(currCmd.getBoxNo()),"cabinet-btn",new EventHandler<ActionEvent>() {
											public void handle(ActionEvent event) {
												Button btn = (Button) event.getSource();
												selected(btn,btn.getAccessibleRoleDescription());
											}
										},false);
									}
								}
							}
							log.info(String.format("状态（response）：端口【%s】- 板卡【%s】- 柜号【%s】-发送成功-返回【%s】.", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo(),(1==currCmd.getStatus()?"已关闭":"未关闭")));
							return 1==currCmd.getStatus();
						} else {
							log.info(String.format("状态（send）：端口【%s】- 板卡【%s】- 柜号【%s】-发送成功但无响应(超时).", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
							return false;
						}
					} else {
						log.info(String.format("状态（send）：端口【%s】- 板卡【%s】- 柜号【%s】-发送失败.", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
						return false;
					}
				}else {
					log.info(String.format("存储：端口【%s】- 板卡【%s】- 柜号【%s】-发送成功但无响应(超时).", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
					return false;
				}
			} else {
				log.info(String.format("存储：端口【%s】- 板卡【%s】- 柜号【%s】-发送失败.", cabinet.get().getName(),currCmd.getBoardNo(),currCmd.getRealNo()));
				return isSucc;
			}
		}
		return false;
	}
	
	private void onReceive(byte[] bget) {
		if (bget != null) {
			if (bget[2] == 0x01) {
				cmdOK = true;
			}
			if (bget[2] == 0x02) {
				cmdOK = true;
				String s1 = Convert.ToString( bget[5], 2);
				String s2 = Convert.ToString( bget[4], 2);
				String s3 = Convert.ToString( bget[3], 2);
				log.info("开关状态(右数)" + (s3 + s2 + s1));
				char[] boxs = Convert.reverse(s3 + s2 + s1);
				
				if(0==currCmd.getModel()) {
					if ('0' == boxs[currCmd.getRealNo()-1]) {
						currCmd.setStatus(1);
					} else {
						currCmd.setStatus(0);
					}
				}
				
				if(1==currCmd.getModel()) {
					if ('1' == boxs[currCmd.getRealNo()-1]) {
						currCmd.setStatus(1);
					} else {
						currCmd.setStatus(0);
					}
				}
			}
			if (bget[2] == 0x3) {
				cmdOK = true;
				String s1 = Convert.ToString( bget[5], 2);
				String s2 = Convert.ToString( bget[4], 2);
				String s3 = Convert.ToString( bget[3], 2);
				log.info("存储状态(右数)" + (s3 + s2 + s1));
				char[] boxs = Convert.reverse(s3 + s2 + s1);
				if ('0' == boxs[currCmd.getRealNo()-1]) {
					currCmd.setStatus(1);
				} else {
					currCmd.setStatus(0);
				}
			}
		}
	}
	
	private boolean isTimeout() {
        long startTime = System.currentTimeMillis();
        while (!cmdOK){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
            }
            long endTime = System.currentTimeMillis();
            if ((endTime-startTime)/1000.0>ShiroUtil.getCabinetTimeout()){
                return true;
            }
        }
		return false;
	}
}
